package org.xx.armory.rpc.routing;

import org.xx.armory.objectparser.ParsedObjectBuilder;
import org.xx.armory.rpc.RpcVerb;

import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.xx.armory.commons.Converter.toIntegerArray;

/**
 * 路由构造器。
 *
 * @author Haart
 * @see org.xx.armory.rpc.routing.Route
 */
final class RouteBuilder
        extends ParsedObjectBuilder<Route> {
    private final RouteData defaults;
    private final RouteData restrictions;
    private String name;
    private String pattern;
    private String className;
    private String methodName;
    private RpcVerb verb;
    private boolean enabled;
    private String description;
    private int[] permissions;

    /**
     * 构造路由构造器。
     */
    public RouteBuilder() {
        defaults = new RouteData(null);
        restrictions = new RouteData(null);
    }

    /**
     * 设置路由的名字。
     *
     * @param name
     *         路由的名字。
     * @return 此构造器本身。
     * @throws NullPointerException
     *         如果参数{@code name}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code name}只包含空白字符。
     */
    public final RouteBuilder setName(
            String name
    ) {
        this.name = name;
        return this;
    }

    /**
     * 设置路由的样式。
     *
     * @param pattern
     *         路由的样式。
     * @return 此构造器本身。
     */
    public final RouteBuilder setPattern(
            String pattern
    ) {
        this.pattern = pattern;
        return this;
    }

    /**
     * 设置路由对应的完整类名。
     *
     * @param className
     *         路由对应的完整类名。
     * @return 此构造器本身。
     */
    public final RouteBuilder setClassName(
            String className
    ) {
        this.className = className;
        return this;
    }

    /**
     * 设置路由对应的方法名。
     *
     * @param methodName
     *         路由对应的方法名。
     * @return 构造器本身。
     */
    public final RouteBuilder setMethodName(
            String methodName
    ) {
        this.methodName = methodName;
        return this;
    }

    /**
     * 设置路由对应的方法名。
     *
     * @param verb
     *         路由对应的请求方法名。
     * @return 构造器本身。
     */
    public final RouteBuilder setVerb(
            RpcVerb verb
    ) {
        this.verb = verb;
        return this;
    }

    /**
     * 设置路由是否可用。
     *
     * @param enabled
     *         路由是否可用。
     * @return 构造器本身。
     */
    public final RouteBuilder setEnabled(
            boolean enabled
    ) {
        this.enabled = enabled;
        return this;
    }

    /**
     * 设置路由的描述。
     *
     * @param description
     *         路由的描述。
     * @return 构造器本身。
     */
    public final RouteBuilder setDescription(
            String description
    ) {
        this.description = description;
        return this;
    }

    /**
     * 设置路由对应的权限列表。
     *
     * @param permissions
     *         路由对应的权限列表，如果是{@code null}或者只包含空白字符则看作{@code null}，即不需要任何权限即可访问。
     * @return 构造器本身。
     */
    public final RouteBuilder setPermissions(
            String permissions
    ) {
        if (isBlank(permissions)) {
            this.permissions = null;
        } else {
            this.permissions = toIntegerArray(permissions.split(","));
        }

        return this;
    }

    /**
     * 添加路由数据的默认值。
     *
     * @param key
     *         路由数据的键
     * @param value
     *         路由数据的默认值。
     * @return 构造器本身。
     */
    public final RouteBuilder addDefault(
            String key,
            String value
    ) {
        this.defaults.put(key, value);
        return this;
    }

    /**
     * 添加路由数据的约束。
     *
     * @param key
     *         路由数据的键
     * @param value
     *         路由数据的约束。
     * @return 构造器本身。
     */
    public final RouteBuilder addRestriction(
            String key,
            final String value
    ) {
        this.restrictions.put(key, value);
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Route build() {
        return new Route(getLineInfo(), this.name, this.pattern,
                         this.className, this.methodName, this.verb, this.enabled, this.description, this.permissions,
                         this.defaults, this.restrictions);
    }
}
